package com.murong.ai.coder.infrastructure.repository;

import com.murong.ai.coder.entity.GlobalProperties;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import com.murong.ai.coder.infrastructure.annotation.JTable;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import java.lang.reflect.Field;

import java.util.Arrays;
import java.util.List;

@Service
public class DaoSupport <T> {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private GlobalProperties globalProperties;

    public T queryOne(T entity) {
        List<T> list = queryForList(entity);
        if (list.isEmpty()) {
            return null;
        }
        if (list.size() > 1) {
            throw new RuntimeException("查询结果不唯一，返回了多条数据");
        }
        return list.get(0);
    }

    public List<T> queryForList(T entity) {
        Class<?> clazz = entity.getClass();
        JTable table = clazz.getAnnotation(JTable.class);
        if (table == null) throw new RuntimeException("缺少JTable注解");
        StringBuilder sql = new StringBuilder("SELECT * FROM " + table.name());
        StringBuilder where = new StringBuilder();
        Object[] params = new Object[clazz.getDeclaredFields().length];
        int idx = 0;
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            try {
                Object value = field.get(entity);
                if (value != null) {
                    if (where.length() == 0) {
                        where.append(" WHERE ");
                    } else {
                        where.append(" AND ");
                    }
                    where.append(camelToSnake(field.getName())).append(" = ?");
                    params[idx++] = value;
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        sql.append(where);
        return (List<T>) jdbcTemplate.query(sql.toString(), Arrays.copyOf(params, idx), new BeanPropertyRowMapper<>(clazz));
    }

    public void insert(T entity) {
        Class<?> clazz = entity.getClass();
        JTable table = clazz.getAnnotation(JTable.class);
        if (table == null) throw new RuntimeException("缺少JTable注解");
        Field[] fields = clazz.getDeclaredFields();
        StringBuilder columns = new StringBuilder();
        StringBuilder values = new StringBuilder();
        Object[] params = new Object[fields.length];
        int idx = 0;
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                Object value = field.get(entity);

                if(StringUtils.equals(field.getName(), "appName") && StringUtils.isBlank((String)value)) {
                    value=globalProperties.getSimpleName();
                }

                if (value != null) {
                    if (columns.length() > 0) {
                        columns.append(",");
                        values.append(",");
                    }
                    columns.append(camelToSnake(field.getName()));
                    values.append("?");
                    params[idx++] = value;
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        String sql = String.format("INSERT INTO %s (%s) VALUES (%s)", table.name(), columns, values);
        Object[] realParams = new Object[idx];
        System.arraycopy(params, 0, realParams, 0, idx);
        jdbcTemplate.update(sql, realParams);
    }

    public void updateByOne(T updateEntity, T whereEntity) {
        Class<?> clazz = updateEntity.getClass();
        JTable table = clazz.getAnnotation(JTable.class);
        if (table == null) throw new RuntimeException("缺少JTable注解");
        Field[] fields = clazz.getDeclaredFields();

        StringBuilder setClause = new StringBuilder();
        Object[] setParams = new Object[fields.length];
        int setIdx = 0;
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                Object value = field.get(updateEntity);
                if (value != null) {
                    if (setClause.length() > 0) {
                        setClause.append(", ");
                    }
                    setClause.append(camelToSnake(field.getName())).append(" = ?");
                    setParams[setIdx++] = value;
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        if (setIdx == 0) {
            throw new RuntimeException("没有需要更新的字段");
        }

        StringBuilder whereClause = new StringBuilder();
        Object[] whereParams = new Object[fields.length];
        int whereIdx = 0;
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                Object value = field.get(whereEntity);
                if (value != null) {
                    if (whereClause.length() > 0) {
                        whereClause.append(" AND ");
                    }
                    whereClause.append(camelToSnake(field.getName())).append(" = ?");
                    whereParams[whereIdx++] = value;
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        if (whereIdx == 0) {
            throw new RuntimeException("没有筛选条件");
        }

        String sql = String.format("UPDATE %s SET %s WHERE %s", table.name(), setClause, whereClause);
        Object[] realParams = new Object[setIdx + whereIdx];
        System.arraycopy(setParams, 0, realParams, 0, setIdx);
        System.arraycopy(whereParams, 0, realParams, setIdx, whereIdx);
        jdbcTemplate.update(sql, realParams);
    }

    /**
     * 驼峰转下划线
     */
    private String camelToSnake(String str) {
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (Character.isUpperCase(c)) {
                result.append('_').append(Character.toLowerCase(c));
            } else {
                result.append(c);
            }
        }
        return result.toString();
    }

}
